﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PicStore.Common;
using PicStore.DAL;
using PicStore.Model;
using PicStore.BLL.Interface;
using WebMatrix.WebData;

namespace PicStore.BLL.Impl
{
    public class UserService : BaseService, IUserService 
    {
        private User BuildUserInfo(UserProfile userProfile)
        {
            var user = new User()
            {
                UserId = userProfile.UserId,
                UserName = userProfile.UserName,
                CreateDate = userProfile.webpages_Membership.CreateDate.GetValueOrDefault(),
                Email = userProfile.webpages_Membership.Email,
                IsDeleted = userProfile.webpages_Membership.IsDeleted ?? false,
                Department = userProfile.webpages_Membership.Department,
                Phone = userProfile.webpages_Membership.Phone,
                Mobile = userProfile.webpages_Membership.Mobile,
            };

            user.Role = (from r in userProfile.webpages_UsersInRoles
                         select BuildRoleInfo(r.webpages_Roles)).FirstOrDefault();

            return user;
        }

        private Role BuildRoleInfo(webpages_Roles roleInfo)
        {
            var role = new Role()
            {
                Id = roleInfo.RoleId,
                Name = roleInfo.RoleName,
            };

            role.Actions = (from r in roleInfo.RoleToAction
                            select BuildActionInfo(r.Action)).ToList();

            return role;
        }

        private ActionDetail BuildActionInfo(DAL.Action actionInfo)
        {
            var result = new ActionDetail()
            {
                ActionId = actionInfo.ActionId,
                ActionUrl = actionInfo.ActionUrl,
            };

            return result;
        }

        public List<User> GetAllUsers(string name)
        {
            var profileList = (from u in dbContext.UserProfile
                               where u.UserName.Contains(name) 
                               && (u.webpages_Membership.IsDeleted == null || u.webpages_Membership.IsDeleted == false)
                               select u).ToList();

            List<User> list = new List<User>();
            foreach (var user in profileList)
            {
                list.Add(BuildUserInfo(user));
            }
            return list;
        }

        public User GetUser(int userId)
        {
            return (from u in dbContext.UserProfile
                    where u.UserId == userId
                    && (u.webpages_Membership.IsDeleted == null || u.webpages_Membership.IsDeleted == false)
                    select BuildUserInfo(u)).FirstOrDefault();
        }

        public User GetUser(string userName)
        {
            return (from u in dbContext.UserProfile
                    where u.UserName == userName
                    select BuildUserInfo(u)).FirstOrDefault();
        }

        private UserProfile GetUserProfilebyId(int userId)
        {
            return (from u in dbContext.UserProfile
                    where u.UserId == userId
                    select u).FirstOrDefault();
        }
        public void ShieldUser(int userId)
        {
            var user = GetUserProfilebyId(userId);
            user.webpages_Membership.IsDeleted = true;
            dbContext.SubmitChanges();
        }

        public void UnShieldUser(int userId)
        {
            var user = GetUserProfilebyId(userId);
            user.webpages_Membership.IsDeleted = false;
            dbContext.SubmitChanges();
        }

        public List<Role> GetRoles()
        {
            return (from r in dbContext.webpages_Roles
                    select new Role
                    {
                        Id = r.RoleId,
                        Name = r.RoleName,
                    }
                ).OrderBy(r => r.Id).ToList();
        }

        public void UpdateUser(int userId, string email, string department, string phone, string mobile, int roleId)
        {
            var user = GetUserProfilebyId(userId);
            if (user != null)
            {
                user.webpages_Membership.Email = email;
                user.webpages_Membership.IsDeleted = false;
                user.webpages_Membership.Department = department;
                user.webpages_Membership.Phone = phone;
                user.webpages_Membership.Mobile = mobile;

                if (user.webpages_UsersInRoles.Count > 0)
                {
                    dbContext.webpages_UsersInRoles.DeleteAllOnSubmit(user.webpages_UsersInRoles);
                }

                webpages_UsersInRoles userToRole = new webpages_UsersInRoles();
                userToRole.UserId = userId;
                userToRole.RoleId = roleId;
                user.webpages_UsersInRoles.Add(userToRole);
                dbContext.webpages_UsersInRoles.InsertOnSubmit(userToRole);
                dbContext.SubmitChanges();
            }
        }

        public void CreateUser(string userName, string password, string email, string department, string phone, string mobile, int roleId)
        {
            // check the connection status, open it if not initialized
            if (dbContext.Connection != null)
            {
                if (dbContext.Connection.State == ConnectionState.Closed)
                    dbContext.Connection.Open();
            }

            // begin a transaction
            DbTransaction tran = dbContext.Connection.BeginTransaction();
            dbContext.Transaction = tran;
            try
            {
                UserProfile au = new UserProfile
                {
                    UserName = userName,
                };
                dbContext.UserProfile.InsertOnSubmit(au);
                dbContext.SubmitChanges();
                Encrypt objEncrypt = new Encrypt();
                password = objEncrypt.Md5Encrypt(objEncrypt.AesEncrypt(password, true));

                var user = GetUserProfilebyId(au.UserId);
                webpages_Membership am = new webpages_Membership()
                {
                    Password = password,
                    CreateDate = DateTime.Now,
                    IsConfirmed = true,
                    IsDeleted = false,
                    Email = email,
                    Department = department,
                    Phone = phone,
                    Mobile = mobile,
                    PasswordFailuresSinceLastSuccess = 0,
                    PasswordSalt = string.Empty,
                    UserId = au.UserId
                };
                user.webpages_Membership = am;
                dbContext.webpages_Membership.InsertOnSubmit(am);

                webpages_UsersInRoles userToRole = new webpages_UsersInRoles();
                userToRole.UserId = au.UserId;
                userToRole.RoleId = roleId;
                user.webpages_UsersInRoles.Add(userToRole);
                dbContext.webpages_UsersInRoles.InsertOnSubmit(userToRole);
                dbContext.SubmitChanges();

                tran.Commit();
            }
            catch (Exception ex)
            {
                tran.Rollback();
                throw ex;
            }
            finally
            {
                if (dbContext.Connection.State == ConnectionState.Open)
                    dbContext.Connection.Close();
            }
        }

        public void ResetPassword(int userId, string password)
        {
            var user = GetUserProfilebyId(userId);
            if (user != null)
            {
                Encrypt objEncrypt = new Encrypt();
                password = objEncrypt.Md5Encrypt(objEncrypt.AesEncrypt(password, true));

                user.webpages_Membership.Password = password;
                dbContext.SubmitChanges();
            }
        }

        public bool ValidateUser(string userName, string password)
        {
            Encrypt objEncrypt = new Encrypt();
            password = objEncrypt.Md5Encrypt(objEncrypt.AesEncrypt(password, true));

            if (dbContext.UserProfile.Any(d => d.UserName == userName))
            {
                if (dbContext.UserProfile.Any(d => d.webpages_Membership.Password == password && d.UserName == userName && d.webpages_Membership.IsDeleted == false)) return true;
            }

            return false;
        }

        public void ChangePassword(string userName, string oldPassword, string newPassword)
        {
            bool result = ValidateUser(userName, oldPassword);
            if (result)
            {
                var user = GetUser(userName);
                ResetPassword(user.UserId, newPassword);
            }
            else
            {
                throw new Exception("Old password is invalid.");
            }
        }
    }
}
